package com.derbysoft.lowcostadapter.dswitch2.service.impl;

import com.derbysoft.lowcostadapter.commons.dto.Search;
import com.derbysoft.lowcostadapter.commons.dto.SearchResponse;
import com.derbysoft.lowcostadapter.commons.exception.HotelNotFoundException;
import com.derbysoft.lowcostadapter.commons.model.Hotel;
import com.derbysoft.lowcostadapter.commons.model.Status;
import com.derbysoft.lowcostadapter.commons.redis.service.HotelCacheService;
import com.derbysoft.lowcostadapter.commons.repository.HotelRepository;
import com.derbysoft.lowcostadapter.commons.utils.ErrorMessageUtils;
import com.derbysoft.lowcostadapter.dswitch2.service.FlushCacheService;
import com.derbysoft.lowcostadapter.dswitch2.service.GetCachedAvailService;
import com.derbysoft.lowcostadapter.dswitch2.service.HotelProviderService;
import com.derbysoft.lowcostadapter.dswitch2.service.helper.Constant;
import com.derbysoft.lowcostadapter.dswitch2.translator.Translator;
import com.derbysoft.lowcostadapter.dswitch2.translator.impl.TranslateHelper;
import com.derbysoft.lowcostadapter.dswitch3.service.AvailRequestMonitor;
import com.derbysoft.lowcostadapter.webservice.LowCostWebService;
import com.derbysoft.remote.dswitch.core.GenericRQ;
import com.derbysoft.remote.dswitch.core.GenericRS;
import com.derbysoft.remote.dswitch.hotel.dto.HotelAvailRQ;
import com.derbysoft.remote.dswitch.hotel.dto.HotelAvailRS;
import com.derbysoft.remote.share.dto.TPAExtensionsDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

@Service("ds2HotelAvailService")
public class HotelAvailServiceImpl
        implements HotelProviderService<GenericRQ<HotelAvailRQ>, GenericRS<HotelAvailRS>> {

    @Autowired
    private GetCachedAvailService getCachedAvailService;

    @Autowired
    private HotelRepository hotelRepository;

    @Autowired
    private HotelCacheService hotelCacheService;

    @Autowired
    @Qualifier("ds2HotelAvailRQTranslator")
    private Translator<GenericRQ<HotelAvailRQ>, Search, Hotel> ds2HotelAvailRQTranslator;

    @Autowired
    private Translator<SearchResponse, GenericRS<HotelAvailRS>, GenericRQ<HotelAvailRQ>> ds2HotelAvailRSTranslator;

    @Autowired
    @Qualifier("searchWebService")
    private LowCostWebService getAvailWebService;

    @Autowired
    private FlushCacheService flushCacheService;

    @Autowired
    private AvailRequestMonitor availRequestMonitor;

    @Override
    public GenericRS<HotelAvailRS> invoke(GenericRQ<HotelAvailRQ> rq) {
        try {
            availRequestMonitor.getTotalCount().incrementAndGet();
            GenericRS<HotelAvailRS> rs = null;
            Hotel hotel = loadHotel(rq.getPayload().getAvailCriteria().getHotelRef().getCode());
            if (fromCache(rq)) {
                rs = getCachedAvailService.getCachedAvailability(rq, hotel);
            }
            if (rs == null) {
                availRequestMonitor.getRealCheckCount().incrementAndGet();

                Search search = ds2HotelAvailRQTranslator.translate(rq, hotel);

                SearchResponse searchResponse = (SearchResponse) getAvailWebService.send(search);

                rs = ds2HotelAvailRSTranslator.translate(searchResponse, rq);

                flushCacheService.flushCache(rq, rs, hotel);
            }
            if (rs.getSuccess() != null && CollectionUtils.isEmpty(rs.getPayload().getHotelAvailRoomStay().getRoomStays())) {
                flushCacheService.removeRates(rq, hotel);

                availRequestMonitor.getNoAllotmentCount().incrementAndGet();
            }
            return rs;
        } catch (Exception ex) {
            return TranslateHelper.buildFailedResponse(ErrorMessageUtils.buildErrorMessage(ex), rq);
        }
    }

    protected Hotel loadHotel(String hotelPassport) {
        Hotel hotel = hotelCacheService.loadByPassport(hotelPassport);
        if (hotel == null) {
            hotel = hotelRepository.findByPassport(hotelPassport, Status.ENABLED);
            if (hotel == null) {
                throw new HotelNotFoundException(hotelPassport);
            }
        }
        return hotel;
    }

    private boolean fromCache(GenericRQ<HotelAvailRQ> rq) {
        TPAExtensionsDTO tpaExtensions = rq.getPayload().getTpaExtensions();
        if (tpaExtensions != null) {
            String disallowCache = tpaExtensions.getElement(Constant.DISALLOW_FROM_CACHE);
            if (Boolean.TRUE.toString().equals(disallowCache)) {
                return false;
            }
        }
        return true;
    }

    public void setGetCachedAvailService(GetCachedAvailService getCachedAvailService) {
        this.getCachedAvailService = getCachedAvailService;
    }

    public void setHotelRepository(HotelRepository hotelRepository) {
        this.hotelRepository = hotelRepository;
    }

    public void setHotelCacheService(HotelCacheService hotelCacheService) {
        this.hotelCacheService = hotelCacheService;
    }

    public void setFlushCacheService(FlushCacheService flushCacheService) {
        this.flushCacheService = flushCacheService;
    }

    public void setDs2HotelAvailRQTranslator(Translator<GenericRQ<HotelAvailRQ>, Search, Hotel> ds2HotelAvailRQTranslator) {
        this.ds2HotelAvailRQTranslator = ds2HotelAvailRQTranslator;
    }

    public void setDs2HotelAvailRSTranslator(Translator<SearchResponse, GenericRS<HotelAvailRS>, GenericRQ<HotelAvailRQ>> ds2HotelAvailRSTranslator) {
        this.ds2HotelAvailRSTranslator = ds2HotelAvailRSTranslator;
    }

    public void setGetAvailWebService(LowCostWebService getAvailWebService) {
        this.getAvailWebService = getAvailWebService;
    }

    public void setAvailRequestMonitor(AvailRequestMonitor availRequestMonitor) {
        this.availRequestMonitor = availRequestMonitor;
    }
}
